#ifndef SRC_LINEAR_LINEAR_HMM_ENGINE
#define SRC_LINEAR_LINEAR_HMM_ENGINE

#include "h_mat_mul.hpp"

class linear_hmme;

template <> struct hmm_status<linear_hmme> : public hmm_status<shmm_engine> {
public:
  hmm_status<linear_hmme>() = delete;
  hmm_status<linear_hmme>(const hmm_status<shmm_engine> &status);

  operator hmm_t() const;
  operator hmm_mt_t() const;
};

class linear_hmme : public shmm_engine {
public:
  /**
   * @brief Construct a new `hypercube_hmme` object.
   *        See `shmm_engine` in `h_mat_mul.hpp` for more detials
   */
  linear_hmme(const hmm_status<shmm_engine> &status);

  ~linear_hmme() = default;

  static long get_expected_nslot(long m, long n, long k);
  static long get_expected_nslot(const cube_signature &eh_mnk);

  /**
   * @brief Using `helib::EncryptedArray` to activate this engine
   *
   * @param ea  class for data-movement operations on arrays of slots
   */
  void register_engine(const helib::EncryptedArray &ea,
                       const cube_signature &cube) override;

  /**
   * @brief Execute Ciphertext GEMMs.
   *        See `shmm_engine` in `h_mat_mul.hpp` for more detials
   */
  void cgemm(MATRIX_TYPE type, helib::Ctxt &AB, const helib::Ctxt &A,
             const helib::Ctxt &B) override;

  hmm_status<linear_hmme> *status() override {
    return static_cast<hmm_status<linear_hmme> *>(status_);
  }
};

#endif /* SRC_LINEAR_LINEAR_HMM_ENGINE */
